namespace XTCast.Mp3
{
	using System;
	using System.IO;
	using XTCast.Mp3;
	//using XTCast.utils;
	
	public class MP3FrameReader:IFrameReader {
		
		private MP3Frame frame;
		private bool readFrame = false;
		private Stream BaseStream;
		private bool readInfo;
		private int sampleRate;
		private int channels;
		private long bytes;
		private TimeSpan secs;
		
		public MP3FrameReader(Stream baseStream):base() {
			BaseStream=baseStream;
			frame = new MP3Frame();
		}

		private bool ReadFrame() {
			while (!readFrame) {
				if (frame.ReadFrame(BaseStream))
					readFrame = !(frame.IsVbrFrame);
				else
					return false;
			}
			SetInfo(frame);
			return true;
		}

		public virtual byte[] ReadFrames(FrameReadInfo info) {
			byte[] b = new byte[info.RequestLength];
			info.ActualLength=0;
			info.ActualFrames=0;
			info.EOF=false;

			while (info.ActualMillis < info.RequestMillis) {
				if (!ReadFrame()) {
					info.EOF = true;
					return b;
				}
				if (info.ActualLength+frame.Size > info.RequestLength )
					return b;
				readFrame = false;
				Array.Copy(frame.Frame, 0, b, info.ActualLength, frame.Size);
				info.ActualLength += frame.Size; info.ActualFrames++;
			}
			return b;
		}

		public virtual void SkipFrames(FrameReadInfo info) {
			info.ActualLength=0;
			info.ActualFrames=0;
			info.EOF=false;

			while (info.ActualMillis < info.RequestMillis) {
				if (!ReadFrame()) {
					info.EOF = true;
					return;
				}
				if (info.ActualLength+frame.Size > info.RequestLength )
					return;
				readFrame = false;
				info.ActualLength += frame.Size; info.ActualFrames++;
			}
			return;
		}

		public void SetInfo(MP3Frame frame) 
		{
			secs+=frame.Length;
			bytes+=frame.Size;
			if (!readInfo) 
			{
				readInfo=true;
				try 
				{
					sampleRate = frame.SampleRate;
					channels = frame.Channels;
				}
				catch (Exception ex)
				{
					Log.Error(this,ex);
				}
			}
		}

		public int SampleRate {
			get {
				ReadFrame();
				return sampleRate;
			}
		}
		
		public int Channels {
			get {
				ReadFrame();
				return channels;
			}
		}
		
		public int AvgBitrate { 
			get { 
				double bits = bytes*8;
				return (int)Math.Round(bits/secs.TotalSeconds); 
			}
		}

		public void Reset() {
			BaseStream.Position=0;
			readFrame = false;
			bytes = 0;
			secs = TimeSpan.Zero;
		}

		public void Close() {
			BaseStream.Close();
		}
	}
}